﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Diplomova_prace
{
    /// <summary>
    /// Třída obsahující konstrukce pro převod do Mathml
    /// </summary>
   public static class Mathml
    {
        public enum TypeBracket
        {
            [Description("")]
            zadne,
            [Description("<mfenced open='(' close=')' separators=''><mrow>")]
            kulate,
            [Description("<mfenced open='[' close=']' separators=''><mrow>")]
            hranate,
            [Description("<mfenced open='{' close='}' separators=''><mrow>")]
            slozene,
            [Description("<mfenced open='&lt' close='&gt' separators=''><mrow>")]
            spicate
        }
        public enum Display
        {
            [Description("\'block\'")]
            block,
            [Description("\'inline\'")]
            inline
        }
        public enum MathVariant
        {
            [Description("\'bold\'")]
            bold,
            [Description("\'italic\'")]
            italic,
            [Description("\'normal\'")]
            normal,
        }
        public enum MathSize
        {
            [Description("\'small\'")]
            small,
            [Description("\'normal\'")]
            normal,
            [Description("\'big\'")]
            big
        }
        public static string Sub(string zaklad, string dolniIndex)
        {
            return "<msub>" + zaklad + Row(dolniIndex) + "</msub>";
        }
        public static string Sup(string zaklad, string exponent)
        {
            return "<msup>" + Row(zaklad) + Row(exponent)+"</msup>";
        }
        public static string SupSub(string zaklad, string dolniIndex, string exponent)
        {
            return "<msubsup>" + zaklad + Row(dolniIndex) + Row(exponent) + "</msubsup>";
        }
        public static string Frac(string citatel, string jmenovatel)
        {
            return "<mfrac><mrow>" + citatel + "</mrow><mrow>" + jmenovatel + "</mrow></mfrac>";
        }
        public static string Root(string zaklad, string IndexOdmocnina)
        {
            return "<mrow><mroot><mrow>" + zaklad + "</mrow>" + IndexOdmocnina+"</mroot></mrow>";
        }
        public static string Sqrt(string zaklad)
        {
            return "<mrow><msqrt>" + zaklad + "</msqrt></mrow>";
        }
        public static string Constant(double num)
        {
            return "<mn>" + num +"</mn>";
        }
        public static string Space(double width = 10)
        {
            return "<mspace width='"+width+"px'/>";
        }
        public static string LineBreak
        {
            get { return "<mspace linebreak='newline'/> "; }
        }
        public static string LZ
        {
            get { return "<mrow><mo>(</mo>"; }
        }
        public static string PZ
        {
            get {return "<mo>)</mo></mrow>";}
        }
        public static string HLZ
        {
            get { return "<mrow ><mo>[</mo>"; }
        }
        public static string HPZ
        {
            get { return "<mo>]</mo></mrow>"; }
        }
        public static string Minus
        {
            get{return "<mo>-</mo>";}
        }
        public static string Plus
        {
            get { return "<mo>+</mo>"; }
        }
        public static string Multiply
        {
            get {return "<mo>"+Symbols.multiplicationDot+"</mo>";}
        }
        public static string Equal
        {
            get { return "<mo>=</mo>"; }
        }
        public static string Mo(string Operator,bool movableLimits=true)
        {
            if (movableLimits)
                return "<mo>" + Operator + "</mo>";
            else
                return "<mo movablelimits='false'>" + Operator + "</mo>";
        }
        public static string Literal(object identifikator, MathVariant variant = MathVariant.italic ,MathSize mathsize= MathSize.normal)
        {
            return "<mi" + " mathvariant=" + variant.ToDescription() + " mathsize=" + mathsize.ToDescription() + ">" + identifikator + "</mi>"; 
        }
        public static string Munderover(string Operator, string Dolnimez, string HorniMez)
        {
            return "<munderover>"+Mo(Operator,false) + Row(Dolnimez) + Row(HorniMez) + "</munderover>";
        }
        public static string Mover(string zaklad, string mover)
        {
            return "<mover align='left' accent=" + "'false'" + ">" + Row(zaklad) +  Literal(Space(5)+mover)+"</mover>";
        }
        public static string HeaderMath(Display display=Display.block)
        {

            return "<math display= " + display.ToDescription() +"><mrow>"; 
        }
        public static string EndMath
        {
            get { return "</mrow></math>"; }
        }
        public static string TableNelinear(List<double> X, List<double> Y, List<string> Expression, bool ShowHeader, int pass)
        {
            int cols = 4;
            int rows = X.Count;
            StringBuilder sb = new StringBuilder();

            if (ShowHeader)
            {
                sb.Append("<mtable mathbackground='#9c9c9c'  frame='solid' equalrows='true' rowlines='solid' columnlines='solid' columnalign='center center center center' width='100%' columnwidth='10% 20% 20% 50%'>");
                sb.Append("<mtr><mtd>" + Literal("n") + "</mtd><mtd>" + Literal("x") + "</mtd><mtd>" + Literal("f") + LZ + Literal("x") + PZ + "</mtd><mtd>" + Literal("Výraz") + "</mtd></mtr>");
                sb.Append("</mtable>");
                sb.Append(Mathml.LineBreak);
            }

            sb.Append("<mtable frame='solid' equalrows='true' rowlines='solid' columnlines='solid' columnalign='center center center center' width='100%' columnwidth='10% 20% 20% 50%'>");
            string tmp = string.Empty;
            for (int i = 0; i < rows; i++)
            {
                sb.Append("<mtr mathbackground='#4c4c4c'>");
                for (int j = 0; j < cols; j++)
                {
                    if (j == 0)
                        tmp = Constant(i + 1 + pass);
                    else if (j == 1)
                        tmp = X[i].NumToMathml();
                    else if (j == 2)
                        tmp = Y[i].NumToMathml();
                    else
                        tmp = Expression[i];
                    sb.Append("<mtd>");
                    sb.Append(tmp);
                    sb.Append("</mtd>");
                }
                sb.Append("</mtr>");
            }
            sb.Append("</mtable>");
            return sb.ToString();
        }
        public static string TableLinearFolder(List<double[,]> input,List<double> accuracy, bool ShowHeader, int pass)
        {
            int cols = 3;
            int rows = input.Count;
            StringBuilder sb = new StringBuilder();
            StringBuilder vektor = new StringBuilder();
            sb.Append("<mtable frame='solid' rowlines='solid' columnlines='solid' columnalign='center center center' columnwidth='50px 550px 250px' displaystyle='true'>");
            if (ShowHeader)
                sb.Append("<mtr><mtd>" + Literal("n") + "</mtd><mtd>" + Sup(Literal("x"), Literal("k")) + "</mtd><mtd>" + Literal(Symbols.euclidNorm) + Sup(Literal("x"), Literal("k")) + Minus + Sup(Literal("x"), Literal("k") + Minus + Constant(1)) + Literal(Symbols.euclidNorm) + "</mtd></mtr>");
            string tmp = string.Empty;
            for (int i = 0; i < rows; i++)
            {
                sb.Append("<mtr>");
                for (int j = 0; j < cols; j++)
                {
                    if (j == 0)
                        tmp = Constant(i + pass);
                    else if (j == 1)
                    {
                        vektor.Append(LZ);
                        for (int k = 0; k < input[i].GetLength(0); k++)
                        {
                            vektor.Append(input[i][k, 0].NumToMathml());
                            if (k + 1 != input[i].GetLength(0))
                                vektor.Append(Space() + Literal(";",MathVariant.normal) + Space());
                        }
                        vektor.Append(PZ);
                        tmp = vektor.ToString();
                        vektor.Clear();
                    }
                    else
                    {
                        int temp = -1;

                        if (ShowHeader)
                        {
                            if (i == 0)
                                continue;
                            else
                                temp = 1;
                        }
                        else
                        {
                                temp = 0;
                        }
                            vektor.Append(accuracy[i-temp].NumToMathml());
                            tmp = vektor.ToString();
                            vektor.Clear();
                        
                    }
                    sb.Append("<mtd>");
                    sb.Append(tmp);
                    sb.Append("</mtd>");
                    tmp = string.Empty;
                }
                sb.Append("</mtr>");
            }
            sb.Append("</mtable>");
            return sb.ToString();
        }
        public static string Table(double[,] input)
        {
            StringBuilder sb = new StringBuilder("<mtable frame='solid' rowlines='solid' columnlines='solid'>");
            int rows = input.GetLength(0);
            int cols = input.GetLength(1);

            for (int i = 0; i < rows;i++)
            {
                sb.Append("<mtr>");
                for (int j = 0; j < cols; j++)
                {
                    sb.Append("<mtd>");
                    sb.Append(input[i, j].NumToMathml());
                    sb.Append("</mtd>");
                }
                sb.Append("</mtr>");
            }
            sb.Append("</mtable>");
            return sb.ToString();
        }
        public static string Matrix(double[,] input, TypeBracket typ = TypeBracket.zadne)
        {
            string zavorky = typ.ToDescription();
            StringBuilder sb = new StringBuilder(zavorky+"<mtable>");
            int rows = input.GetLength(0);
            int cols = input.GetLength(1);

            for (int i = 0; i < rows; i++)
            {
                sb.Append("<mtr>");
                for (int j = 0; j < cols; j++)
                {
                    sb.Append("<mtd>");
                    sb.Append(input[i, j].NumToMathml());
                    sb.Append("</mtd>");
                }
                sb.Append("</mtr>");
            }
            sb.Append("</mtable>");
            if (zavorky != string.Empty)
                sb.Append(EndMfenced);
            return sb.ToString();
        }
        public static string Matrix(string[,] input,Expression expression, TypeBracket typ = TypeBracket.zadne)
        {
            string zavorky = typ.ToDescription();
            StringBuilder sb = new StringBuilder(zavorky + "<mtable>");
            int rows = input.GetLength(0);
            int cols = input.GetLength(1);

            for (int i = 0; i < rows; i++)
            {
                sb.Append("<mtr>");
                for (int j = 0; j < cols; j++)
                {
                    sb.Append("<mtd>");
                    sb.Append(expression.TextToMathml(input[i, j], Display.block,false));
                    sb.Append("</mtd>");
                }
                sb.Append("</mtr>");
            }
            sb.Append("</mtable>");
            if (zavorky != string.Empty)
                sb.Append(EndMfenced);
            return sb.ToString();
        }
        public static string AdvMatrix(double[,] inputL, double[,] inputR, TypeBracket typ = TypeBracket.kulate)
        {
            StringBuilder sb = new StringBuilder();
            string zavorky = typ.ToDescription();
            sb.Append(zavorky + "<mtable columnlines='solid'><mtr><mtd>" + Matrix(inputL) + "</mtd><mtd>" + Matrix(inputR) + "</mtd></mtr></mtable>");
            if (zavorky != string.Empty)
                sb.Append(EndMfenced);
            return sb.ToString();
        }
        public static string AdvMatrix(string[,] inputL, string[,] inputR, Expression expr, TypeBracket typ = TypeBracket.kulate)
        {
            StringBuilder sb = new StringBuilder();
            string zavorky = typ.ToDescription();
            sb.Append(zavorky + "<mtable columnlines='solid'><mtr><mtd>" + Matrix(inputL,expr) + "</mtd><mtd>" + Matrix(inputR,expr) + "</mtd></mtr></mtable>");
            if (zavorky != string.Empty)
                sb.Append(EndMfenced);
            return sb.ToString();
        }
        public static string EndMfenced
        {
            get { return "</mrow></mfenced>"; }
        }
        public static string Text(string text)
        {
            return "<mtext>"+text+"</mtext>";
        }
        public static string Row(string obj)
        {
            return "<mrow>" + obj + "</mrow>";
        }
/*        public static string Zavorky(TypZavorky typ)
        {
              string zavorky = string.Empty;
            if (typ == TypZavorky.kulate)
                zavorky = "<mfenced open='(' close=')' separators=''><mrow>";
            else if (typ == TypZavorky.hranate)
                zavorky = "<mfenced open='[' close=']' separators=''><mrow>";
            else if (typ == TypZavorky.slozene)
                zavorky = "<mfenced open='{' close='}' separators=''><mrow>";
            else if (typ == TypZavorky.spicate)
                zavorky = "<mfenced open='&lt;' close='&gt;'  separators=''><mrow>";
            return zavorky;
        }
 */

        /// <summary>
        /// Slouží pro převod double do mathml
        /// </summary>
        /// <param name="num">číslo pro převod do mathml</param>
        /// <param name="sign">znaménko, které se zobrazí u kladného čísla</param>
        /// <param name="zero">znaménko, které se zobrazí u nuly</param>
        /// <returns></returns>
        public static string NumToMathml(this double num, string sign = null, string zero = null)
        {
            num = Math.Round(num, Extension.countDecimalPlaces);
            double prah = 0.00005;
            double HorniCelaCast = Math.Ceiling(num);
            double DolniCelaCast = Math.Floor(num);
            if (HorniCelaCast != num || DolniCelaCast != num)
            {
                double rozdilH = Math.Abs(Math.Abs(HorniCelaCast) - Math.Abs(num));
                double rozdilL = Math.Abs(Math.Abs(DolniCelaCast) - Math.Abs(num));
                if (rozdilH < prah)
                    num = HorniCelaCast;
                if (rozdilL < prah)
                    num = DolniCelaCast;
            }
            StringBuilder sb = new StringBuilder();
            if (num < 0)
                sb.Append("<mo>-</mo>" + "<mn>" + ((double)Math.Abs(num)).MyToString() + "</mn>");
            else if (num == 0)
                if (zero != null)
                    sb.Append(@"<mo>" + zero + "</mo><mn>" + num.MyToString() + "</mn>");
                else
                    sb.Append(@"<mo></mo><mn>" + num.MyToString() + "</mn>");
            else
                sb.Append(@"<mo>" + sign + "</mo><mn>" + num.MyToString() + "</mn>");

            return sb.ToString().Replace("<mo></mo>", string.Empty);
        }
        /// <summary>
        /// převede záporné číslo do MathML a obalí závorkami, kladné číslo převede do MathML
        /// </summary>
        /// <param name="num"></param>
        /// <returns></returns>
        public static string Bracket(this double num)
        {
            if (num < 0)
                return "<mrow><mo>(</mo>" + num.NumToMathml() + "<mo>)</mo></mrow>";
            else
                return num.NumToMathml();
        }


    }
}
  
 
